//
// Created by abstergo on 24-6-7.
//

#ifndef ARRAYINL_CUH
#define ARRAYINL_CUH

namespace {
inline void checkIndex(CONST size_t &input, CONST size_t &inside) {
  if (input >= inside) {
	throw tbs::base_error("out of range for size");
  }
}
}

namespace tbs::structs {

template<typename T, size_t L>
CONST T &Array<T, L>::operator[](const size_t &index) CONST {
  return _data[index];
}

template<typename T, size_t L>
size_t Array<T, L>::cap() const noexcept {
  return L;
}

template<typename T, size_t L>
size_t Array<T, L>::size() const noexcept {
  return this->_size;
}

template<typename T, size_t L>
T &Array<T, L>::operator[](const size_t &index) {
  checkIndex(index, size());
  return this->_data[index];
}

template<typename T, size_t L>
void Array<T, L>::append(const T &d) {
  checkIndex(size() + 1, cap());
  this->_data[this->_size++] = d;
}

template<typename T, size_t L>
void Array<T, L>::append(T &&d) {
  checkIndex(size(), cap());
  this->_data[this->_size++] = d;
}

template<typename T, size_t L>
size_t Array<T, L>::removeIf(
	std::function<bool(const T &, const size_t &)> &&predict) {
  size_t s = size();
  size_t removeCount = 0, left = 0;
  T arr[L];
  for (size_t i = 0; i < s; ++i) {
	if (predict(_data[i], i)) {
	  removeCount++;
	} else {
	  arr[left++] = _data[i];
	}
  }
  for (size_t i = 0; i < left; i++) {
	_data[i] = arr[i];
  }
  // 更新数组大小
  _size = left;

  return removeCount;
}

template<typename T, size_t L>
size_t Array<T, L>::removeByIndexs(std::initializer_list<size_t> &&indexs) {
  std::set<size_t> s(indexs);
  return removeIf([&s](const T &v, const size_t &i) {
	return s.contains(i);
  });
}

template<typename T, size_t L>
size_t Array<T, L>::removeByValue(std::initializer_list<T> &&values) {
  std::set<T> s(values);
  return removeIf([&s](const T &v, const size_t &i) {
	return s.contains(v);
  });
}

template<typename T, size_t L>
Array<T, L>::Array(const std::initializer_list<T> &list) {
  for (T &i : list) {
	append(i);
  }
}

template<typename T, size_t L>
Array<T, L>::Array(const size_t &init)
	:_size(init) {
}

template<typename T, size_t L>
void Array<T, L>::insertList(CONST std::initializer_list<T> &l, CONST size_t &index) {
  size_t ls = l.size(), nowSize = size();
  size_t ed = index + ls, md = nowSize - index;
  auto beg = l.begin();
  checkIndex(ed, cap());
  for (size_t i = 0; i < md; i++) {
	_data[nowSize + ls - 1 - i] = _data[nowSize - i - 1];
  }
  for (size_t i = 0; i < ls; i++) {
	_data[index + i] = *(beg + i);
  }
  _size += ls;

}

template<typename T, size_t L>
iterators::PointerIterator<T> Array<T, L>::begin() NO_EXCEPT {
  return iterators::PointerIterator<T>(_data, size());
}

template<typename T, size_t L>
iterators::PointerIterator<T> Array<T, L>::end() NO_EXCEPT {
  return iterators::PointerIterator<T>(_data, size(), size() - 1);
}

}
#endif //ARRAYINL_CUH